package com.weareint.common.utils;

import groovy.lang.GroovyClassLoader;
import lombok.extern.slf4j.Slf4j;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.springframework.util.DigestUtils;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.ConcurrentHashMap;

/** Groovy Script Tool */
@Slf4j
public abstract class GroovyScriptUtil {

    private static GroovyClassLoader groovyClassLoader = null;

    private static final ConcurrentHashMap<String, Class> groovyScriptTestMap =
            new ConcurrentHashMap<>();

    private static GroovyClassLoader getGroovyClassLoader() {
        if (null == groovyClassLoader) {
            synchronized (GroovyScriptUtil.class) {
                if (null == groovyClassLoader) {
                    CompilerConfiguration configuration = new CompilerConfiguration();
                    configuration.setSourceEncoding("UTF-8");
                    groovyClassLoader =
                            new GroovyClassLoader(
                                    GroovyScriptUtil.class.getClassLoader(), configuration);
                }
            }
        }
        return groovyClassLoader;
    }

    public static Class scriptToClass(String groovyScript) {
        String md5 = DigestUtils.md5DigestAsHex(groovyScript.getBytes(StandardCharsets.UTF_8));
        if (!groovyScriptTestMap.containsKey(md5)) {
            synchronized (md5.intern()) {
                if (!groovyScriptTestMap.containsKey(md5)) {
                    String fileName =
                            "script"
                                    + System.currentTimeMillis()
                                    + Math.abs(groovyScript.hashCode())
                                    + ".groovy";
                    groovyScriptTestMap.put(md5, scriptToClass(groovyScript, fileName));
                }
            }
        }
        return groovyScriptTestMap.get(md5);
    }

    private static Class scriptToClass(String groovyScript, String fileName) {
        return getGroovyClassLoader().parseClass(groovyScript, fileName);
    }

    /**
     * <pre>
     *      用于测试Groovy脚本的合法性
     * </pre>
     * @param groovyScript groovy script
     * @return groovy class
     */
    public static Class testScriptToClass(String groovyScript) {
        String md5 = DigestUtils.md5DigestAsHex(groovyScript.getBytes(StandardCharsets.UTF_8));
        if (!groovyScriptTestMap.containsKey(md5)) {
            groovyScriptTestMap.put(
                    md5, scriptToClass(groovyScript, "validate_groovy_syntax.groovy"));
        }
        return groovyScriptTestMap.get(md5);
    }
}
